<?php
/**************************************************************************
 *
 *   Copyright 2010 American Public Media Group
 *
 *   This file is part of AIR2.
 *
 *   AIR2 is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   AIR2 is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with AIR2.  If not, see <http://www.gnu.org/licenses/>.
 *
 *************************************************************************/

require_once 'AIR2_CRUD_Controller.php';
require_once 'tank/Discriminator.php';

/**
 * Import Controller
 *
 * @package default
 */
class Import_Controller extends AIR2_CRUD_Controller {

    public $base_model_name = 'Tank';
    public $base_view_name  = 'import';
    public $exposed_relations = array(
        'sources' => 'TankSource',
    );
    public $valid_args = array(
        'status' => 'query_status',
    );
    public $column_whitelist = array('tf_fact_id', 'tank_actm_id');

    /* conflict-resolver parameters */
    protected $op_var = 'ops';
    protected $op_map = array(
        'R' => AIR2_DISCRIM_REPLACE,
        'I' => AIR2_DISCRIM_IGNORE,
        'A' => AIR2_DISCRIM_ADD,
    );


    /**
     *
     *
     * @param AIR2_Query $q
     * @param boolean $deeply (optional)
     */
    protected function _add_query_load_related(&$q, $deeply=true) {
        if (!$this->rel_uri) {
            $q->leftJoin('a.Organization o');
            $q->leftJoin('a.Project p');
            $q->leftJoin('a.User u');
            $q->leftJoin('a.ActivityMaster m');

            // add subquery counts
            $sub = 'select count(*) from tank_source where tsrc_tank_id = a.tank_id';
            $q->addSelect("($sub) as count_total");
            $this->extra_field_defs[] = array('name' => 'count_total', 'type' => 'int');
            $type_counts = array(
                TankSource::$STATUS_NEW => 'count_new',
                TankSource::$STATUS_CONFLICT => 'count_conflict',
                TankSource::$STATUS_LOCKED => 'count_locked',
                TankSource::$STATUS_DONE => 'count_done',
                TankSource::$STATUS_ERROR => 'count_error',
            );
            foreach ($type_counts as $code => $name) {
                $q->addSelect("($sub and tsrc_status = '$code') as $name");
                $this->extra_field_defs[] = array('name' => $name, 'type' => 'int');
            }

            // flatten org/prj/user uuid
            $q->addSelect('o.org_uuid as org_uuid');
            $this->extra_field_defs []= array('name' => 'org_uuid');
            $q->addSelect('p.prj_uuid as prj_uuid');
            $this->extra_field_defs []= array('name' => 'prj_uuid');
            $q->addSelect('u.user_uuid as user_uuid');
            $this->extra_field_defs []= array('name' => 'user_uuid');
        }
        elseif ($this->rel_uri == 'sources') {
            $q->leftJoin('a.Source s');
            $q->leftJoin('a.TankFact tf');
            $q->leftJoin('tf.Fact f');
            $q->leftJoin('tf.AnalystFV afv');
            $q->leftJoin('tf.SourceFV sfv');
        }
        parent::_add_query_load_related($q, $deeply);
    }


    /**
     * Custom data and views for html requests
     *
     * @param associative-array $data
     * @param string  $view_name
     * @return string html body
     */
    public function get_html_body($data, $view_name=null) {
        if ($this->base_uuid && !$this->rel_uri) {
            // tank_sources
            $q = $this->build_query($this->base_uuid, 'sources');
            $q->limit(25);
            $tsrc_data = $this->fetch_data($q, true, true);

            $data = array(
                'tank_uuid' => $this->base_uuid,
                'tank_url'  => $this->uri_for('import').'/'.$this->base_uuid,
                'tank_data' => $data,
                'tsrc_data' => $tsrc_data,
            );
        }
        return parent::get_html_body($data, $view_name);
    }


    /**
     * Set the page title
     *
     * @param array   $head
     * @return array
     */
    public function get_html_head($head=array()) {
        if ($this->base_uuid) {
            $name = $this->_find_base()->tank_file_name;
            $head['title'] = AIR2_SYSTEM_DISP_NAME." - Import: $name";
        }
        return $head;
    }


    /**
     * Query by status.  Each passed character will be included, and a blank
     * string will return all statuses.
     *
     * @param AIR2_Query $q
     * @param string  $status_codes
     */
    public function query_status($q, $status_codes) {
        if ($this->rel_uri == 'sources') {
            if ($status_codes && strlen($status_codes) > 0) {
                $chars = str_split($status_codes);
                $q->andWhereIn('a.tsrc_status', $chars);
            }
        }
    }


    /**
     * URL-accessible method for resolving conflicts on a TankSource. This can
     * be accessed at:
     *      POST => import/<TANK_UUID>/sources/<TSRC_ID>/resolve
     *
     * This method accepts the POST parameter 'ops', containing a json-encoded
     * array of model operations to resolve the conflict.  For instance:
     *      $ops = array(
     *          'Source'   => 'R',   //replace
     *          'Fact.3'   => 'I',   //ignore
     *          'SrcEmail' => 'A',   //add
     *      );
     *
     * @param string  $tank_uuid
     * @param string  $tsrc_id
     */
    public function resolve_conflicts($tank_uuid, $tsrc_id) {
        $q = $this->build_query($tank_uuid, 'sources', $tsrc_id);
        $q->setConnection(AIR2_DBManager::get_master_connection());
        $tsrc = $q->fetchOne();
        if (!$tsrc) {
            $this->show_404();
        }
        elseif ($tsrc->tsrc_status != TankSource::$STATUS_CONFLICT) {
            show_error("TankSource cannot be resolved: not in conflict status!", 412);
        }

        // get POST parameters (ops)
        $my_ops = array();
        $post_ops = $this->input->post('ops');
        $json_ops = json_decode($post_ops);

        if ($post_ops && $json_ops) {
            foreach ($json_ops as $model => $op) {
                if (isset($this->op_map[$op])) {
                    $my_ops[$model] = $this->op_map[$op];
                }
            }
        }

        // run the discriminator on this single tank_source
        $d = new Discriminator();
        $lock = $d->run($tsrc->tsrc_tank_id, $tsrc->tsrc_id, $my_ops);
        if (!$lock) {
            $this->success = false;
            $this->message = 'Unable to lock tank for resolution';
        }
        else {
            if ($d->error_count > 0) {
                $this->success = false;
                $this->message = 'Errors resolving source';
            }
            elseif ($d->conflict_count > 0) {
                $this->success = false;
                $this->message = 'Conflicts not resolved';
            }
            else {
                $this->success = true;
                $this->message = 'Imported '.$d->done_count.' source';
            }
        }

        // refetch the item
        $data = $this->fetch_data($q);
        $this->crud_response($data);
    }


}
